﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Drawing.Printing;

namespace Paint
{
    class FillColor
    {
        // Tô màu cho một vùng kín
        // Điểm màu được tô được trùng với điểm màu ban đầu khi click
        public void FloodFill(Bitmap bm, int x, int y, Color new_color)
        {
            // Lấy điểm màu mới và củ
            byte old_r = bm.GetPixel(x, y).R;
            byte old_g = bm.GetPixel(x, y).G;
            byte old_b = bm.GetPixel(x, y).B;
            byte new_r = new_color.R;
            byte new_g = new_color.G;
            byte new_b = new_color.B;

            // Nếu màu đầu tiên đã giống màu cần tô rồi thì dừng
            if ((old_r == new_r) && (old_g == new_g) && (old_b == new_b)) return;

            // Tạo stack để lưu các tọa độ cần tô màu mới
            Stack<Point> points = new Stack<Point>();
            points.Push(new Point(x, y));
            bm.SetPixel(x, y, new_color);

            // Tạo một mảng đối tượng byte Bitmap32 để lưu các điểm ảnh dạng ARGB
            Bitmap32 bm32 = new Bitmap32(bm);
            //Khóa ảnh ban đầu lại
            bm32.LockBitmap();

            while (points.Count > 0)
            {
                Point pt = points.Pop();
                if (pt.X > 0) CheckPoint(bm32, points, pt.X - 1, pt.Y, old_r, old_g, old_b, new_r, new_g, new_b);
                if (pt.Y > 0) CheckPoint(bm32, points, pt.X, pt.Y - 1, old_r, old_g, old_b, new_r, new_g, new_b);
                if (pt.X < bm.Width - 1) CheckPoint(bm32, points, pt.X + 1, pt.Y, old_r, old_g, old_b, new_r, new_g, new_b);
                if (pt.Y < bm.Height - 1) CheckPoint(bm32, points, pt.X, pt.Y + 1, old_r, old_g, old_b, new_r, new_g, new_b);
            }

            // unlock, gán lại ảnh bitmap đã xử lý về cho ảnh bitmap củ
            bm32.UnlockBitmap();
        }

        // Kiểm tra xem, tại tọa độ mới (tăng/giảm x,y) điểm màu có còn trùng với điểm màu ban đầu hay không
        // Nếu trùng thì add vào stack là tọa độ đó cần tô màu mới
        private void CheckPoint(Bitmap32 bm32, Stack<Point> points, int x1, int y1, byte old_r, byte old_g, byte old_b, byte new_r, byte new_g, byte new_b)
        {
            //Công thức tìm vị trí của tọa độ (x,y) trong mảng byte của ảnh bitmap
            int pix = y1 * bm32.RowSizeBytes + x1 * Bitmap32.PixelSizeBytes;
            byte b = bm32.ImageBytes[pix];
            byte g = bm32.ImageBytes[pix + 1];
            byte r = bm32.ImageBytes[pix + 2];

            if ((r == old_r) && (g == old_g) && (b == old_b))
            {
                points.Push(new Point(x1, y1));
                bm32.ImageBytes[pix] = new_b;
                bm32.ImageBytes[pix + 1] = new_g;
                bm32.ImageBytes[pix + 2] = new_r;
            }
        }
    }
}
